package com.gdatacloud;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;

import org.apache.ibatis.exceptions.PersistenceException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import com.alibaba.druid.pool.DataSourceClosedException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.gdata.base.exception.RException;
import com.gdata.base.facade.R;
import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;

import lombok.extern.slf4j.Slf4j;

@RestControllerAdvice
@Slf4j
public class GExceptionHandler {

	/**
	 * 处理自定义异常
	 */
	@ExceptionHandler(RException.class)
	public R<String> handleRRException(RException e) {
		R<String> r = new R<String>(e.getCode()).msg(e.getMessage());
		return r;
	}

	@ExceptionHandler(DuplicateKeyException.class)
	public R<String> handleDuplicateKeyException(DuplicateKeyException e) {
		log.error(e.getMessage(), e);
		return R.error("数据库中已存在该记录");
	}

	@ExceptionHandler(HttpMessageNotReadableException.class)
	public R<String> handleException(HttpMessageNotReadableException e) {
		log.error(e.getMessage(), e);
		return R.error("请求体格式不对，请检查");
	}

	@ExceptionHandler(JsonMappingException.class)
	public R<String> handleException(JsonMappingException e) {
		log.error(e.getMessage(), e);
		return R.error("json解析异常，请检查数据格式");
	}
	@ExceptionHandler(BindException.class)
	public R<String> handleException(BindException e) {
		log.error(e.getMessage(), e.getCause().getMessage());
		return R.error("参数的数据类型异常，");
	}
	@ExceptionHandler(MethodArgumentTypeMismatchException.class)
	public R<String> handleException(MethodArgumentTypeMismatchException e) {
		log.error(e.getMessage(), e.getCause().getMessage());
		return R.error("参数的数据类型异常，" + e.getName() + "不能为" + e.getValue());
	}
	@ExceptionHandler(NumberFormatException.class)
	public R<String> handleException(NumberFormatException e) {
		log.error(e.getMessage(), e);
		return R.error("数据类型异常");
	}
	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
	public R<String> handleException(HttpRequestMethodNotSupportedException e) {
		log.error(e.getMessage(), e);
		return R.error("http动词不合法：" + e.getMessage());
	}
	
	@ExceptionHandler(DataSourceClosedException.class)
	public R<String> handleException(DataSourceClosedException e) {
		log.error(e.getMessage(), e);
		return R.error("数据源异常，请联系管理员");
	}
	
	@ExceptionHandler(MaxUploadSizeExceededException.class)
	public R<String> maxUploadSizeExceededException(MaxUploadSizeExceededException e) {
		log.error("上传文件过大，超出设定值", e);
		return R.error("上传文件过大");
	}
	

	@ExceptionHandler(PersistenceException.class)
	public R handlePersistenceException(PersistenceException e , HttpServletRequest request) {
		return R.error("操作失败，请检查依赖");
	}
	
	/**
	 * 可能主键插入重复或者其他SQL错误
	 * @param e
	 * @param request
	 * @return
	 */
	@ExceptionHandler(MySQLIntegrityConstraintViolationException.class)
	public R<String> handleMySQLIntegrityConstraintViolationException(MySQLIntegrityConstraintViolationException e) {
		//String uri = request.getRequestURI();
		Map<String, Object> content = new HashMap<>();
		//content.put("uri", uri);
		String message = e.iterator().next().getMessage();
		content.put("content", message);
		log.error(e.getMessage(), e);
		return R.error(content.toString());
	}
	/**
	 * 参数校验错误
	 * @param e
	 * @return
	 */
	@ExceptionHandler(MethodArgumentNotValidException.class)
	public R<String> argumentValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        
//        String errorMesssage = "";
        StringBuilder sr = new StringBuilder();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sr.append(fieldError.getDefaultMessage()).append("");
        }
//        for (ObjectError error : this.bindingResult.getAllErrors()) {
//			sb.append("[").append(error).append("] ");
//		}
		log.error(e.getMessage());
		return R.error(sr.toString());
	}
	
	@ExceptionHandler(ValidationException.class)
    public R<String> handle(ValidationException exception) {
        if(exception instanceof ConstraintViolationException){
            ConstraintViolationException exs = (ConstraintViolationException) exception;

            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            for (ConstraintViolation<?> item : violations) {
                //打印验证不通过的信息
//                System.out.println(item.getMessage());
                return R.error(item.getMessage());
            }
        }
        return R.error("参数校验不通过");
    }
	@ExceptionHandler(MissingServletRequestParameterException.class)
	public R<String> handleMissingServletRequestParameterException(MissingServletRequestParameterException exception) {
		return R.error("参数校验不通过:" + exception.getMessage());
	}
	
	@ExceptionHandler(Exception.class)
	public R<String> handleException(Exception e) {
		log.error(e.getMessage(), e);
		return R.error("操作失败，请稍后重试");
	}
}
